package com.ruoyi.core.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.LeaveTypeConstants;
import com.ruoyi.common.constant.ProcessInstanceConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.ApplyStatus;
import com.ruoyi.common.enums.GlobalSettingsType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.core.service.AttendanceCalculationService;
import com.ruoyi.out.domain.AnnualLeaveRecord;
import com.ruoyi.out.domain.LeaveInstance;
import com.ruoyi.out.domain.ProcInstance;
import com.ruoyi.out.domain.UserOvertimeLeave;
import com.ruoyi.out.mapper.AnnualLeaveRecordMapper;
import com.ruoyi.out.mapper.LeaveInstanceMapper;
import com.ruoyi.out.mapper.ProcInstanceMapper;
import com.ruoyi.out.mapper.UserOvertimeLeaveMapper;
import com.ruoyi.out.service.IUserOvertimeLeaveService;
import com.ruoyi.out.service.impl.BaseService;
import com.ruoyi.system.domain.LeaveType;
import com.ruoyi.system.mapper.GeneralConfigurationMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import static com.ruoyi.common.enums.GlobalSettingsType.ATTENDANCE_TIME;

/**
 * @author Yuan
 * @description
 * @date 2022/10/8 17:39
 */
@Service
public class AttendanceCalculationServiceImpl extends BaseService implements AttendanceCalculationService {
    @Autowired
    private IUserOvertimeLeaveService userOvertimeLeaveService;
    @Autowired
    private GeneralConfigurationMapper generalConfigurationMapper;
    @Autowired
    private ProcInstanceMapper procInstanceMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private AnnualLeaveRecordMapper annualLeaveRecordMapper;

    /**
     * 获取某人当月法定工作日加班小时  legalWorkingDay
     */
    @Override
    public Double getLegalWorkingDayOvertimeHour(Long userId,String dateStr) {
        Map<String,Object> map = new HashMap<>();
        map.put("userId",userId);
        map.put("processKey", ProcessInstanceConstants.REQUEST_FOR_OVERTIME);
        map.put("applyState", ApplyStatus.EXAMINATION_AND_APPROVAL_BY.getStatus());
        map.put("searchTime",dateStr);
        List<ProcInstance> procInstanceList = procInstanceMapper.selectAll(map);
        AtomicReference<Double> atomicReference = new AtomicReference<>(0D);
        if(procInstanceList != null && procInstanceList.size() > 0){
            for (ProcInstance procInstance : procInstanceList) {
                Map<String,Object> tempMap = (Map<String, Object>) JSON.parse(procInstance.getProcData());
                String compensate = (String) tempMap.get("compensate");
                if("2".equals(compensate)){
                    //加班费
                    atomicReference.set(procInstance.getLegalWorkingDay().doubleValue() +atomicReference.get());
                }
            }
        }
        return atomicReference.get();
    }
    /**
     * 获取当月休息日加班小时数  restDay
     * @param userId
     * @return
     */
    @Override
    public Double getRestDayOvertimeHour(Long userId,String dateStr) {
        Map<String,Object> map = new HashMap<>();
        map.put("userId",userId);
        map.put("processKey", ProcessInstanceConstants.REQUEST_FOR_OVERTIME);
        map.put("applyState", ApplyStatus.EXAMINATION_AND_APPROVAL_BY.getStatus());
        map.put("searchTime",dateStr);
        List<ProcInstance> procInstanceList = procInstanceMapper.selectAll(map);
        AtomicReference<Double> atomicReference = new AtomicReference<>(0D);
        if(procInstanceList != null && procInstanceList.size() > 0){
            for (ProcInstance procInstance : procInstanceList) {
                Map<String,Object> tempMap = (Map<String, Object>) JSON.parse(procInstance.getProcData());
                String compensate = (String) tempMap.get("compensate");
                if("2".equals(compensate)){
                    //加班费
                    atomicReference.set(procInstance.getRestDay().doubleValue() +atomicReference.get());
                }
            }
        }
        return atomicReference.get();
    }
    /**
     * 某人当月法定休假日加班小时数   officialHoliday
     */
    @Override
    public Double getOfficialHolidayDayOvertimeHour(Long userId,String dateStr) {
        Map<String,Object> map = new HashMap<>();
        map.put("userId",userId);
        map.put("processKey", ProcessInstanceConstants.REQUEST_FOR_OVERTIME);
        map.put("applyState", ApplyStatus.EXAMINATION_AND_APPROVAL_BY.getStatus());
        map.put("searchTime",dateStr);
        List<ProcInstance> procInstanceList = procInstanceMapper.selectAll(map);
        AtomicReference<Double> atomicReference = new AtomicReference<>(0D);
        if(procInstanceList != null && procInstanceList.size() > 0){
            for (ProcInstance procInstance : procInstanceList) {
                Map<String,Object> tempMap = (Map<String, Object>) JSON.parse(procInstance.getProcData());
                String compensate = (String) tempMap.get("compensate");
                if("2".equals(compensate)){
                    //加班费
                    atomicReference.set(procInstance.getOfficialHoliday().doubleValue() +atomicReference.get());
                }
            }
        }
        return atomicReference.get();
    }

    /****************************************  请  假  *************************************/
    /**
     * 某人当年年累计病假小时数
     */
    @Override
    public Double getSickLeaveHourForYear(Long userId,String year) {
        //获取本年的病假时长
        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowYear(userId, year);
        AtomicReference<Double> atomicReference = new AtomicReference<Double>(0D);
        if(userOvertimeLeaveList != null && userOvertimeLeaveList.size() > 0){
            userOvertimeLeaveList.forEach(attendance -> {
                atomicReference.set(atomicReference.get() + attendance.getSickLeave());
            });
        }
        return atomicReference.get();
    }
    /**
     * 某人当月累计病假小时数
     */
    @Override
    public Double getSickLeaveHourForMonth(Long userId,String dateStr) {
        //获取本月的病假时长
        UserOvertimeLeave userOvertimeLeave = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowDate(userId, dateStr);
        return userOvertimeLeave.getSickLeave();
    }

    /**
     * 本年的事假天数
     * @param userId
     * @return
     */
    @Override
    public Double getAnnualPersonnelLeaveDay(Long userId,String year) {

        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowYear(userId, year);
        AtomicReference<Double> atomicReference = new AtomicReference<>(0D);
        double everyAttendanceTime = Double.parseDouble(generalConfigurationMapper.selectHolidaySettingByType(ATTENDANCE_TIME.getType()));
        userOvertimeLeaveList.forEach(userOvertimeLeave -> atomicReference.set(userOvertimeLeave.getPersonalLeaveTime() +atomicReference.get()));
        return atomicReference.get() / everyAttendanceTime;
    }

    /**
     * 某人当年年累计事假小时
     */
    @Override
    public Double getAnnualPersonnelLeaveHour(Long userId,String year){
        //获取本年的事假时长
        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowYear(userId, year);
        AtomicReference<Double> atomicReference = new AtomicReference<Double>(0D);
        if(userOvertimeLeaveList != null && userOvertimeLeaveList.size() > 0){
            userOvertimeLeaveList.forEach(attendance -> {
                atomicReference.set(atomicReference.get() + attendance.getPersonalLeaveTime());
            });
        }
        return atomicReference.get();
    }

    /**
     * 某人当月月累计事假天数
     */
    @Override
    public Double getPersonnelLeaveDayForMonth(Long userId,String dateStr) {
        Double personnelLeaveHourForMonth = getPersonnelLeaveHourForMonth(userId,dateStr);
        double everyAttendanceTime = Double.parseDouble(generalConfigurationMapper.selectHolidaySettingByType(ATTENDANCE_TIME.getType()));
        double v = personnelLeaveHourForMonth / everyAttendanceTime;
        return v;
    }

    /**
     * 获取工龄
     */
    @Override
    public BigDecimal getEmployeeAge(Long userId) {
        SysUser sysUser = sysUserMapper.selectUserById(userId);
        Date entryTime = sysUser.getEntryTime();
        Date nowDate = DateUtils.getNowDate();
        return yearCompare(entryTime,nowDate);
    }

    /**
     * 获取当月事假小时数
     * @param userId
     * @return
     */
    @Override
    public Double getPersonnelLeaveHourForMonth(Long userId,String dateStr) {
        //获取本月的事假时长
        UserOvertimeLeave userOvertimeLeave = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowDate(userId, dateStr);
        return userOvertimeLeave.getPersonalLeaveTime();
    }

    @Override
    public Double getBreastFeedingLeaveHourForYear(Long userId,String year) {

        //获取本年的哺乳假时长
        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowYear(userId, year);
        AtomicReference<Double> atomicReference = new AtomicReference<Double>(0D);
        if(userOvertimeLeaveList != null && userOvertimeLeaveList.size() > 0){
            userOvertimeLeaveList.forEach(attendance -> {
                atomicReference.set(atomicReference.get() + attendance.getBreastFeedingLeave());
            });
        }
        return atomicReference.get();
    }

    @Override
    public Double getPersonnelLeaveHourBeforeDate(Long userId, String dateStr) {
        String year = dateStr.substring(0,4);
        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeBeforeDate(userId, year, dateStr);
        AtomicReference<Double> atomicReference = new AtomicReference<Double>(0D);
        if(userOvertimeLeaveList != null && userOvertimeLeaveList.size() > 0){
            userOvertimeLeaveList.forEach(attendance -> {
                atomicReference.set(atomicReference.get() + attendance.getPersonalLeaveTime());
            });
        }
        return atomicReference.get();
    }

    @Override
    public Double getSickLeaveHourBeforeDate(Long userId, String dateStr) {
        String year = dateStr.substring(0,4);
        List<UserOvertimeLeave> userOvertimeLeaveList = userOvertimeLeaveService.selectUserOvertimeBeforeDate(userId, year, dateStr);
        AtomicReference<Double> atomicReference = new AtomicReference<Double>(0D);
        if(userOvertimeLeaveList != null && userOvertimeLeaveList.size() > 0){
            userOvertimeLeaveList.forEach(attendance -> {
                atomicReference.set(atomicReference.get() + attendance.getSickLeave());
            });
        }
        return atomicReference.get();
    }

    @Override
    public UserOvertimeLeave getAttendanceData(Long userId,String dateStr) {
        //查询用户加班及事假时长
        UserOvertimeLeave userOvertimeLeave = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowDate(userId,dateStr);
        if(StringUtils.isNull(userOvertimeLeave)){
            Double allAttendanceTime = userOvertimeLeaveService.getAllAttendanceTime(dateStr);
            //插入数据
            userOvertimeLeave = new UserOvertimeLeave();
            userOvertimeLeave.setId(IdUtils.fastSimpleUUID());
            userOvertimeLeave.setUserId(userId);
            userOvertimeLeave.setShouldAttendanceTime(allAttendanceTime);
            userOvertimeLeave.setAttendanceTime(dateStr);
            userOvertimeLeaveService.insertUserOvertimeLeave(userOvertimeLeave);
        }
        return userOvertimeLeave;
    }

    @Override
    public BigDecimal annualLeaveDay(Long userId) {
        AnnualLeaveRecord annualLeaveRecord = annualLeaveRecordMapper.selectAnnualLeaveRecordByUserIdAndYear(userId, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy")));
        if(annualLeaveRecord != null && annualLeaveRecord.getAnnualLeaveDay() != null){
            return annualLeaveRecord.getAnnualLeaveDay();
        }else{
            return new BigDecimal(0D);
        }
    }

    @Override
    public BigDecimal getBasicSalaryRateToBreastFeeding() {
        BigDecimal bigDecimal = new BigDecimal(generalConfigurationMapper.selectHolidaySettingByType(GlobalSettingsType.WOMAN_LACTATION_LEAVE_BASE_SALARY_RATIO.getType()));
        return bigDecimal.setScale(2,RoundingMode.HALF_UP);
    }

    @Override
    public BigDecimal getBasicMeritSalaryRateToBreastFeeding() {
        BigDecimal bigDecimal = new BigDecimal(generalConfigurationMapper.selectHolidaySettingByType(GlobalSettingsType.WOMAN_LACTATION_LEAVE_BASE_PERFORMANCE_SALARY_RATIO.getType()));
        return bigDecimal.setScale(2,RoundingMode.HALF_UP);

    }

    @Override
    public BigDecimal getRewardPerformanceRateToBreastFeeding() {
        BigDecimal bigDecimal = new BigDecimal(generalConfigurationMapper.selectHolidaySettingByType(GlobalSettingsType.WOMAN_LACTATION_LEAVE_BASE_REWARD_SALARY_RATIO.getType()));
        return bigDecimal.setScale(2,RoundingMode.HALF_UP);
    }

    @Override
    public BigDecimal getAttendanceTimeEveryDay() {
        BigDecimal attendanceTime = new BigDecimal(generalConfigurationMapper.selectHolidaySettingByType(ATTENDANCE_TIME.getType()));
        return attendanceTime.setScale(2, RoundingMode.HALF_UP);
    }

    @Override
    public Double getBreastFeedingLeaveHourForMonth(Long userId,String dateStr) {

        //获取本月的哺乳假时长
        UserOvertimeLeave userOvertimeLeave = userOvertimeLeaveService.selectUserOvertimeLeaveByUserIdAndNowDate(userId, dateStr);
        return userOvertimeLeave.getBreastFeedingLeave();
    }

    /**
     *
     * @param fromDate  入职时间
     * @param toDate 当前时间
     * @return
     */
    public BigDecimal yearCompare(Date fromDate,Date toDate){
        Calendar  from  =  Calendar.getInstance();
        from.setTime(fromDate);
        Calendar  to  =  Calendar.getInstance();
        to.setTime(toDate);
        int fromYear = from.get(Calendar.YEAR);
        int fromMonth = from.get(Calendar.MONTH);

        int toYear = to.get(Calendar.YEAR);
        int toMonth = to.get(Calendar.MONTH);

        int year = toYear  -  fromYear;
        int month = toMonth  - fromMonth;

        return new BigDecimal(year + Double.valueOf(month) / 12.0 ).setScale(1,BigDecimal.ROUND_HALF_UP);
    }
}
